package com.example.qxfw.qhtztj.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.dmgis.util.StringUtil;
import com.example.qxfw.qhtztj.entity.SumHumidityData;
import com.example.qxfw.qhtztj.entity.WeatherData;
import com.example.qxfw.qhtztj.entity.vo.SumHumidityDataVo;
import com.example.qxfw.qhtztj.entity.vo.WeatherDataVo;
import com.example.qxfw.qhtztj.entity.vo.WindDrectionDataVo;
import com.example.qxfw.qhtztj.mapper.SumHumidityDataMapper;
import com.example.qxfw.qhtztj.mapper.SumRainYearDataMapper;
import com.example.qxfw.qhtztj.service.SumHumidityDataService;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author pengdongdong
 * @description public
 */
@Service
public class SumHumidityDataServiceImpl implements SumHumidityDataService {

    /**
     * 站点id
     * 伊宁：51431
     * 伊宁县：51434
     * 察布查尔国家气象观测站：51430
     * 霍城：51329
     * 巩留：51435
     * 新源：51436
     * 昭苏：51437
     * 特克斯：51438
     * 尼勒克：51433
     * 霍尔果斯：51328
     * 奎屯：暂无
     */

    //连续天数
    private static final int THRESHOLD = 5;
    //温度标准
    private static final double TEMPERATURE_THRESHOLD = 0;

    private static final String[] stationId = {
            "51431",
            "51434",
            "51430",
            "51329",
            "51435",
            "51436",
            "51437",
            "51438",
            "51433",
            "51428"
    };

    @Resource
    private SumHumidityDataMapper sumHumidityDataMapper;

    @Resource
    private SumRainYearDataMapper sumRainYearDataMapper;

//    public List<SumHumidityDataVo> getSumHumidityData(SumHumidityData sumHumidityData) {
//        List<SumHumidityDataVo> listData = new ArrayList<>();
//        if (StringUtil.judgeStringNull(sumHumidityData.getYear())) {
//            String[] year = sumHumidityData.getYear().split(",");
//            sumHumidityData.setStartYear(year[0]);
//            sumHumidityData.setEndYear(year[1]);
//        }
//        List<SumHumidityDataVo> list = sumHumidityDataMapper.getSumHumidityData(sumHumidityData);
//        if (!CollectionUtils.isEmpty(list)) {
//
//            // 计算平均数
//            Double sum = list.stream()
//                    .mapToDouble(SumHumidityDataVo::getSumvalue)
//                    .sum() / list.size();
//            BigDecimal annualValue = new BigDecimal(sum).setScale(1, BigDecimal.ROUND_HALF_UP);
//            list.forEach(l -> {
//                l.setAnnualValue(annualValue.doubleValue());
//                BigDecimal percentageDeviation = new BigDecimal((l.getSumvalue() / sum - 1) * 100)
//                        .setScale(1, BigDecimal.ROUND_HALF_UP);
//                l.setPercentageDeviation(percentageDeviation.doubleValue());
//            });
//            return list;
//        }
//        return list;
//    }

    private static final String[] sumIndicatorNameList = {"雨日", "暴雨日", "高温日数", "高温日", "低温日数", "大风日数", "大风日", "暴雪日", "积雪日", "雪日", "大雾日", "冰雹日", "降水日"};

    /**
     * 气候数据统计
     *
     * @param sumHumidityData
     * @return
     */
    @DS("master")
    public List<SumHumidityDataVo> getData(SumHumidityData sumHumidityData) {
        if (StringUtil.judgeStringNull(sumHumidityData.getYear())) {
            String[] year = sumHumidityData.getYear().split(",");
            sumHumidityData.setStartYear(year[0]);
            sumHumidityData.setEndYear(year[1]);
        }
        String sumIndicatorName = sumHumidityData.getSumindicatorname();
        // 降水
        if (sumHumidityData.getDataType() == 1 &&
                !Arrays.asList(sumIndicatorNameList).contains(sumIndicatorName)) {
            return percentageDeviation(sumRainYearDataMapper.getRainData(sumHumidityData));
        }
        if (Arrays.asList(sumIndicatorNameList).contains(sumIndicatorName)) {
            return percentageDeviation(sumRainYearDataMapper.getRainDataDaySum(sumHumidityData));
        }

        // 查询气温和气压
        if (sumHumidityData.getDataType() == 2 || sumHumidityData.getDataType() == 8) {
            return percentageDeviation(sumHumidityDataMapper.getTempData(sumHumidityData));
        }
        if (sumHumidityData.getDataType() == 7) {
            if (sumIndicatorName.equals("最大积雪深度") || sumIndicatorName.equals("雪压"))
                return percentageDeviation(sumRainYearDataMapper.getSnowData(sumHumidityData));
        }
        if (sumHumidityData.getDataType() == 9) {
            if(sumIndicatorName.equals("连阴雨日")){
                return percentageDeviation(sumRainYearDataMapper.getRainCloudyData(sumHumidityData));
            }
        }
        return getSumHumidityData(sumHumidityData);
    }

    /**
     * 查询降水，湿度
     *
     * @param sumHumidityData
     * @return
     */
    private List<SumHumidityDataVo> getSumHumidityData(SumHumidityData sumHumidityData) {

        List<SumHumidityDataVo> list = sumHumidityDataMapper.getSumHumidityData(sumHumidityData);
        if (!CollectionUtils.isEmpty(list)) {

            List<SumHumidityDataVo> listData = new ArrayList<>();
            List<SumHumidityDataVo> listData2;
            // 如果查全州，过滤非伊犁的地区，目前为了快速，后续可修改SQL优化
            if (!StringUtil.judgeStringNull(sumHumidityData.getStationname())) {
                list.forEach(l -> {
                    if (Arrays.asList(stationId).contains(l.getStationid())) {
                        listData.add(l);
                    }
                });
                listData2 = listData;
            } else {
                listData2 = list;
            }
            List<SumHumidityDataVo> listDataNew = listData;
            if (!CollectionUtils.isEmpty(listData2)) {
                // 去掉伊犁以外的地区，可优化SQL去重
                List<SumHumidityDataVo> listDataThis = listData2.stream().collect(Collectors.collectingAndThen(
                        Collectors.toCollection(() -> new TreeSet<>(Comparator
                                .comparing(SumHumidityDataVo::getYear))), ArrayList::new
                ));
                // 如果查询全州，计算总数
                if (!StringUtil.judgeStringNull(sumHumidityData.getStationname())
                        && ("总雨量".equals(sumHumidityData.getSumindicatorname()))) {
                    listDataThis.forEach(l -> {
                        Double n = 0.0;
                        for (int i = 0; i < listDataNew.size(); i++) {
                            if (l.getYear().equals(listDataNew.get(i).getYear())) {
                                n += listDataNew.get(i).getSumvalue();
                            }
                        }
                        BigDecimal value = new BigDecimal(n / 11).setScale(1, BigDecimal.ROUND_HALF_UP);
                        l.setSumvalue(value.doubleValue());
                    });
                }

                // 计算平均数
                Double sum = listDataThis.stream()
                        .mapToDouble(SumHumidityDataVo::getSumvalue)
                        .sum() / listDataThis.size();
                BigDecimal annualValue = new BigDecimal(sum).setScale(1, BigDecimal.ROUND_HALF_UP);
                listDataThis.forEach(l -> {
                    l.setAnnualValue(annualValue.doubleValue());
                    // 计算距平百分率
                    BigDecimal percentageDeviation = new BigDecimal((l.getSumvalue() / sum - 1) * 100)
                            .setScale(1, BigDecimal.ROUND_HALF_UP);
                    l.setPercentageDeviation(percentageDeviation.doubleValue());
                });
                return listDataThis;
            }
        }
        return list;
    }

    /**
     * 计算距平百分率
     *
     * @param list
     * @return
     */
    private List<SumHumidityDataVo> percentageDeviation(List<SumHumidityDataVo> list) {
        if (!CollectionUtils.isEmpty(list)) {
            // 计算平均数
            Double sum = list.stream()
                    .mapToDouble(SumHumidityDataVo::getSumvalue)
                    .sum() / list.size();
            BigDecimal annualValue = new BigDecimal(sum).setScale(1, BigDecimal.ROUND_HALF_UP);
            list.forEach(l -> {
                // 计算距平百分率
                Double s = sum >= 0 ? sum : -sum;
                int n = sum >= 0 ? 1 : -1;
                l.setAnnualValue(annualValue.doubleValue());
                //如果sum总和为0则距平百分率设为0
                BigDecimal percentageDeviation = new BigDecimal(0);
                if (s != 0)
                    percentageDeviation = new BigDecimal((l.getSumvalue() / s - n) * 100)
                            .setScale(1, BigDecimal.ROUND_HALF_UP);
                l.setPercentageDeviation(percentageDeviation.doubleValue());
            });
        }
        return list;
    }

    /**
     * 计算风向/频率距平百分率
     *
     * @param list
     * @return
     */
    private List<WindDrectionDataVo> windPercentageDeviation(List<WindDrectionDataVo> list) {
        //计算单个风向的常年值,为单个风向频率和除总年数
        //北风频率总和

        int sumN = 0;
        //东北风频率总和
        int sumEN = 0;
        //东风频率总和
        int sumE = 0;
        //东南风频率总和
        int sumES = 0;
        //南风频率总和
        int sumS = 0;
        //西南风频率总和
        int sumWS = 0;
        //西风频率总和
        int sumW = 0;
        //西北风频率总和
        int sumWN = 0;
        //总年数
        Set<Integer> setYear = new HashSet<>();
        for (WindDrectionDataVo windDrectionDataVo : list) {
            switch (windDrectionDataVo.getWindDirection()) {
                case "北":
                    sumN += windDrectionDataVo.getFrequency();
                    break;
                case "东北":
                    sumEN += windDrectionDataVo.getFrequency();
                    break;
                case "东":
                    sumE += windDrectionDataVo.getFrequency();
                    break;
                case "东南":
                    sumES += windDrectionDataVo.getFrequency();
                    break;
                case "南":
                    sumS += windDrectionDataVo.getFrequency();
                    break;
                case "西南":
                    sumWS += windDrectionDataVo.getFrequency();
                    break;
                case "西":
                    sumW += windDrectionDataVo.getFrequency();
                    break;
                case "西北":
                    sumWN += windDrectionDataVo.getFrequency();
                    break;
            }
            setYear.add(Integer.parseInt(windDrectionDataVo.getYear()));
        }
        for (WindDrectionDataVo windDrectionDataVo : list) {
            switch (windDrectionDataVo.getWindDirection()) {
                case "北":
                    windDrectionDataVo.setAnnualValue(Math.round((double) sumN / setYear.size() * 10.0) / 10.0);
                    break;
                case "东北":
                    windDrectionDataVo.setAnnualValue(Math.round((double) sumEN / setYear.size() * 10.0) / 10.0);
                    break;
                case "东":
                    windDrectionDataVo.setAnnualValue(Math.round((double) sumE / setYear.size() * 10.0) / 10.0);
                    break;
                case "东南":
                    windDrectionDataVo.setAnnualValue(Math.round((double) sumES / setYear.size() * 10.0) / 10.0);
                    break;
                case "南":
                    windDrectionDataVo.setAnnualValue(Math.round((double) sumS / setYear.size() * 10.0) / 10.0);
                    break;
                case "西南":
                    windDrectionDataVo.setAnnualValue(Math.round((double) sumWS / setYear.size() * 10.0) / 10.0);
                    break;
                case "西":
                    windDrectionDataVo.setAnnualValue(Math.round((double) sumW / setYear.size() * 10.0) / 10.0);
                    break;
                case "西北":
                    windDrectionDataVo.setAnnualValue(Math.round((double) sumWN / setYear.size() * 10.0) / 10.0);
                    break;
            }
            Double sum = windDrectionDataVo.getAnnualValue();
            Double s = sum >= 0 ? sum : -sum;
            int n = sum >= 0 ? 1 : -1;
            //如果sum总和为0则距平百分率设为0
            BigDecimal percentageDeviation = new BigDecimal(0);
            if (s != 0)
                percentageDeviation = new BigDecimal((windDrectionDataVo.getFrequency() / s - n) * 100)
                        .setScale(1, BigDecimal.ROUND_HALF_UP);
            windDrectionDataVo.setPercentageDeviation(percentageDeviation.doubleValue());
        }
        return list;
    }
    public List<WeatherDataVo> getWeatherData(SumHumidityData sumHumidityData) {
        List<WeatherDataVo> list = new ArrayList<>();
        List<WeatherData> list_data = new ArrayList<>();
        //获取查找的开始结束年份
        if (StringUtil.judgeStringNull(sumHumidityData.getYear())) {
            String[] year = sumHumidityData.getYear().split(",");
            sumHumidityData.setStartYear(year[0]);
            sumHumidityData.setEndYear(year[1]);
        }
        else return null;
        list_data = sumRainYearDataMapper.getWinterData(sumHumidityData);
        if(sumHumidityData.getSumindicatorname().equals("入冬期")) {
            //删除第一年的1,2月和最后一年+1的12月的数据
            String startYear = sumHumidityData.getStartYear();
            String endYear = sumHumidityData.getEndYear();
            for(Iterator<WeatherData> it = list_data.iterator(); it.hasNext();){
                WeatherData weatherData = it.next();
                if((weatherData.getYear() == Integer.parseInt(startYear)  &&
                        (weatherData.getMonth() == 1 || weatherData.getMonth() == 2)) ||
                        (weatherData.getYear() == Integer.parseInt(endYear) + 1 &&
                                weatherData.getMonth() == 12))
                    it.remove();
            }
            list = getWeatherDataByWinter(list_data);
        }
        //开春期,初霜期，终霜期
        else
            list = sumRainYearDataMapper.getWeatherData(sumHumidityData);
        return list;
    }

    /**
     * 查找入冬期
     * @param records
     * @return
     */
    public List<WeatherDataVo> getWeatherDataByWinter(List<WeatherData> records){
        //按地区分组并排序
        List<WeatherDataVo> result = new ArrayList<WeatherDataVo>();
        Map<String, List<WeatherData>> groupedByStation = records.stream()
                .collect(Collectors.groupingBy(WeatherData::getStationname,
                        Collectors.collectingAndThen(Collectors.toList(), lst ->{
                            lst.sort(Comparator.comparing(WeatherData::getDate));
                            return lst;
                        })));

        //计算每个地区的入冬开始的日期
        Map<String, Map<Integer, LocalDate>> winterStarts = new HashMap<>();
        for(Map.Entry<String, List<WeatherData>> stationEntry : groupedByStation.entrySet()){
            List<WeatherData> weatherDataList = stationEntry.getValue();
            String station = stationEntry.getKey();
            Map<Integer,LocalDate> yearStarts = new TreeMap<>();
            //将数据按年份分开
            Map<Integer,List<WeatherData>> dataByYear = separateByYear(weatherDataList);
            for(Map.Entry<Integer, List<WeatherData>> yearEntry : dataByYear.entrySet()){
                Integer year = yearEntry.getKey();
                LocalDate start = findStationWinterStart(yearEntry.getValue());
                if(start != null){
                    yearStarts.put(year, start);
                }
            }
            winterStarts.put(station,yearStarts);
        }
        for(String station : winterStarts.keySet()) {
            for(int year : winterStarts.get(station).keySet()) {
                result.add(new WeatherDataVo(String.valueOf(year), winterStarts.get(station).get(year).toString(), station));
            }
        }
        return result;
    }

    /**
     * 将数据按年份分开，并且1,2月的数据将其归类到前一年
     * @param records
     * @return
     */
    private static Map<Integer, List<WeatherData>> separateByYear(List<WeatherData> records){
        Map<Integer, List<WeatherData>> byYear = new TreeMap<>();
        for(WeatherData weatherData : records){
            int keyYear = weatherData.getMonth() == 12 ? weatherData.getYear() : weatherData.getYear() - 1;
            byYear.computeIfAbsent(keyYear, k -> new ArrayList<>()).add(weatherData);
        }
        return  byYear;
    }

    /**
     * 从12月到次年2月的数据中查找入冬期
     * @param records
     * @return
     */
    private static LocalDate findStationWinterStart(List<WeatherData> records) {
        //将数据按照时间排序
        records.sort(new Comparator<WeatherData>() {
            @Override
            public int compare(WeatherData o1, WeatherData o2) {
                return o1.getDate().compareTo(o2.getDate());
            }
        });
        for(int i = 0; i <= records.size() - THRESHOLD; i++){
            boolean isWinterStart = true;
            for(int j = 0; j < THRESHOLD; j++) {
                if (records.get(i + j).getSumvalue() >= TEMPERATURE_THRESHOLD) {
                    isWinterStart = false;
                    break;
                }
            }
            if(isWinterStart){
                return records.get(i).getDate();
            }

        }
        return null;
    }
    public List<WindDrectionDataVo> getWindDrectionData(SumHumidityData sumHumidityData){
        if (StringUtil.judgeStringNull(sumHumidityData.getYear())) {
            String[] year = sumHumidityData.getYear().split(",");
            sumHumidityData.setStartYear(year[0]);
            sumHumidityData.setEndYear(year[1]);
        }
        return windPercentageDeviation(sumHumidityDataMapper.getWindDrectionData(sumHumidityData));
    }
}
